package org.seedltd.upms.service.impl.detection;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.seedltd.base.exception.BusinessException;
import org.seedltd.core.base.BasePage;
import org.seedltd.core.base.BaseServiceImpl;
import org.seedltd.core.utils.*;
import org.seedltd.mail.service.MailService;
import org.seedltd.springsecurity.SeedltdUserDetails;
import org.seedltd.springsecurity.utils.IPUtils;
import org.seedltd.springsecurity.utils.UserUtils;
import org.seedltd.upms.constant.GlobalConst;
import org.seedltd.upms.enums.EnableStatus;
import org.seedltd.upms.enums.OrderStatus;
import org.seedltd.upms.mapper.detection.DetectionOrderMapper;
import org.seedltd.upms.model.detection.dto.RefundOrderDTO;
import org.seedltd.upms.model.detection.entity.*;
import org.seedltd.upms.model.detection.form.*;
import org.seedltd.upms.model.detection.vo.*;
import org.seedltd.upms.model.sys.entity.SysUser;
import org.seedltd.upms.model.sys.vo.SysAttachmentVO;
import org.seedltd.upms.service.detection.*;
import org.seedltd.upms.service.sys.SysAttachmentService;
import org.seedltd.upms.service.sys.SysUserService;
import org.seedltd.upms.utils.SnowFlake;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 订单管理业务实现
 * 
 * @author laizuan
 * @since 2021/07/31
 */
@Service
@AllArgsConstructor
public class DetectionOrderServiceImpl extends BaseServiceImpl<DetectionOrderMapper, DetectionOrder>
    implements DetectionOrderService {

    private final DetectionOrderTracingService detectionOrderTracingService;
    private final DetectionProductService detectionProductService;
    private final DetectionOrderLogService detectionOrderLogService;
    private final SysUserService sysUserService;
    private final DetectionQrcodeService detectionQrcodeService;
    private final DetectionOrderBindingService detectionOrderBindingService;
    private final DetectionTerminalService detectionTerminalService;
    private final MailService mailService;
    private final DetectionMpConfigService detectionMpConfigService;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private final DetectionOrderRefundService detectionOrderRefundService;
    private final DetectionWeCharPayService detectionWeCharPayService;
    private final DetectionTubeService detectionTubeService;
    private final SysAttachmentService sysAttachmentService;
    private final VendingMachineApiService vendingMachineApiService;
    private final DetectionTerminalPipelineService detectionTerminalPipelineService;

    @Override
    public DetectionOrder getById(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public DetectionOrder getByOrderNo(String tradeNo) {
        return q().eq(DetectionOrder::getTradeNo, tradeNo).selectOne();
    }

    @Override
    public DetectionOrder getNotifyExportOrder(Long id, boolean isBg) {
        DetectionOrder detectionOrder = baseMapper.selectById(id);

        if (GlobalConst.YES.equals(detectionOrder.getDeleteFlag())) {
            throw new BusinessException("订单已删除不能操作");
        }

        Integer state = detectionOrder.getState();
        if (!OrderStatus.UN_DELIVER.getValue().equals(state)) {
            throw new BusinessException("订单状态【%s】不能出货，请联系客服", EnumUtils.getEnumDescByKey(OrderStatus.class, state));
        }

        Long vendingMachineId = detectionOrder.getVendingMachineId();
        if (vendingMachineId == null) {
            throw new BusinessException("非售卖机购买，不能出货。");
        }

        if (!isBg) {
            // 后台发货不做限制
            if (GlobalConst.YES.equals(detectionOrder.getExportFlag())) {
                throw new BusinessException("已出货，不能重复出货。");
            }

            if (GlobalConst.YES.equals(detectionOrder.getRefundFlag())) {
                throw new BusinessException("订单已退款不能发货。");
            }
        }

        return detectionOrder;
    }

    @Override
    public boolean updateOrderProduct(Long orderId, Long productId, String state, String checkResult) {
        return baseMapper.updateOrderProduct(orderId, productId, state, checkResult) > 0;
    }

    @Override
    public boolean checkUnBanding() {
        Long userId = UserUtils.getUserId();
        // @formatter:off
        return  q()
                .eq(DetectionOrder::getCreateBy, userId)
                .eq(DetectionOrder::getBindingState, GlobalConst.NO)
                .eq(DetectionOrder::getDeleteFlag, GlobalConst.NO)
                .ge(DetectionOrder::getState, OrderStatus.UN_DELIVER.getValue())
                .checkExists();
        // @formatter:on
    }

    @Override
    public DetectionTubeVO getReportOrder(Long orderId) {
        DetectionOrder pojo = baseMapper.selectById(orderId);
        if (pojo == null) {
            throw new BusinessException("未找到订单信息，请联系客服");
        }
        if (GlobalConst.YES.equals(pojo.getDeleteFlag())) {
            throw new BusinessException("订单已删除不能操作");
        }
        DetectionTube detectionTube = detectionTubeService.findByQrCodeId(pojo.getQrcodeId());
        DetectionTubeVO detectionTubeVO = new DetectionTubeVO();
        detectionTubeVO.setCheckResult(detectionTube.getCheckResult());
        detectionTubeVO.setDisturbResultState(detectionTube.getDisturbResultState());
        detectionTubeVO.setDisturbResultScope(detectionTube.getDisturbResultScope());

        List<SysAttachmentVO> attachmentList = sysAttachmentService.listByLinkedId(detectionTube.getId());
        SysAttachmentVO sysAttachmentVO = attachmentList.get(0);
        detectionTubeVO.setAttachment(sysAttachmentVO);

        List<DetectionOrderProductVO> product = convert(orderId, true);
        detectionTubeVO.setDetectionOrderProductList(product);
        return detectionTubeVO;
    }

    private List<DetectionOrderProductVO> convert(Long orderId, boolean appendNull) {
        List<DetectionOrderProductVO> product = baseMapper.listProductByOrderId(orderId);
        for (DetectionOrderProductVO detectionOrderProductVO : product) {
            String itemNameVal = detectionOrderProductVO.getItemNameVal();
            String[] items = StringUtils.split(itemNameVal, ",");
            if (items.length == 0) {
                continue;
            }
            List<DetectionOrderProductVO.ProductItem> productItemList =
                Lists.newArrayListWithExpectedSize(items.length);
            DetectionOrderProductVO.ProductItem productItem;
            for (String item : items) {
                String[] values = StringUtils.split(item, ":");
                productItem = new DetectionOrderProductVO.ProductItem();
                if (values.length == 1) {
                    productItem.setName(values[0]);
                    productItemList.add(productItem);
                } else if (values.length == 2) {
                    productItem.setName(values[0]);
                    productItem.setValue(values[1]);
                    productItemList.add(productItem);
                }
            }
            if (appendNull && productItemList.size() > 1) {
                // 添加null对象，方便小程序显示
                if (productItemList.size() % 2 != 0) {
                    productItemList.add(new DetectionOrderProductVO.ProductItem(" ", " ", null));
                }
            }
            detectionOrderProductVO.setItemNameVal(null);
            detectionOrderProductVO.setProductItemList(productItemList);
        }
        return product;
    }

    @Override
    public DetectionOrder getByTubeId(Long tubeId) {
        return q().eq(DetectionOrder::getTubeId, tubeId).selectOne();
    }

    @Override
    public List<DetectionOrderProductVO> listProductByOrderId(Long orderId) {
        return baseMapper.listProductByOrderId(orderId);
    }

    @Override
    public boolean updatePayStatus(QueryVO query, Long orderId) {
        String jsonStr = query.getBody();
        WxPayOrderQueryV3Result v3Result = JsonUtils.toBean(jsonStr, WxPayOrderQueryV3Result.class);
        DetectionOrder detectionOrder = new DetectionOrder();
        detectionOrder.setId(orderId);
        detectionOrder.setState(OrderStatus.UN_DELIVER.getValue());
        detectionOrder.setTransactionId(v3Result.getTransactionId());
        this.updateById(detectionOrder);
        detectionOrderTracingService.updateTracing(orderId, OrderStatus.UN_DELIVER.getValue(), "Auto", new Date(),
            false, null);

        StringJoiner stringJoiner = new StringJoiner("；", "[", "]");
        stringJoiner.add("交易类型: " + v3Result.getTradeType());
        stringJoiner.add("交易状态：" + v3Result.getTradeState());
        stringJoiner.add("支付完成时间：" + v3Result.getSuccessTime());

        detectionOrderLogService.add("系统主动查询", new Date(), orderId, stringJoiner.toString());
        return false;
    }

    @Override
    public DetectionOrderVO findById(final Long id) {
        DetectionOrder pojo = baseMapper.selectById(id);
        if (pojo == null) {
            return null;
        }
        DetectionOrderVO resultVo = new DetectionOrderVO();
        BeanUtils.copyProperties(pojo, resultVo);

        Long qrcodeId = pojo.getQrcodeId();
        if (qrcodeId != null) {
            DetectionQrcodeVO qrcode = detectionQrcodeService.findById(qrcodeId);
            resultVo.setDetectionQrcode(qrcode);
        }
        Long vendingMachineId = pojo.getVendingMachineId();
        if (vendingMachineId != null) {
            DetectionTerminal terminal = detectionTerminalService.getById(vendingMachineId);
            resultVo.setVendingMachine(terminal);
        }

        Long recycleBinId = pojo.getRecycleBinId();
        if (recycleBinId != null) {
            DetectionTerminal terminal = detectionTerminalService.getById(recycleBinId);
            resultVo.setRecycleBin(terminal);
        }

        DetectionOrderBindingVO binding = detectionOrderBindingService.findByOrderId(id);
        resultVo.setDetectionOrderBinding(binding);

        List<DetectionOrderProductVO> product = this.convert(id, false);

        resultVo.setDetectionOrderProductList(product);

        List<DetectionOrderTracingVO> tracingList = detectionOrderTracingService.listByOrderId(id);
        resultVo.setDetectionOrderTracingList(tracingList);

        List<DetectionOrderLog> detectionOrderLogs = detectionOrderLogService.listByOrderId(id);
        resultVo.setDetectionOrderLogList(detectionOrderLogs);

        if (GlobalConst.YES.equals(pojo.getRefundFlag())) {
            DetectionOrderRefundVO refundVO = detectionOrderRefundService.findByOrderId(id);
            resultVo.setOrderRefund(refundVO);
        }

        return resultVo;
    }

    @Override
    @Transactional
    public Long add(DetectionOrderForm form, HttpServletRequest request) throws Exception {
        List<DetectionProduct> detectionProducts = detectionProductService.listByIds(form.getProductIdList());
        if (CollectionUtils.isEmpty(detectionProducts)) {
            throw new BusinessException("选择的产品无效，请刷新页面后重新选择");
        }

        int size = detectionProducts.size();
        List<DetectionOrderProductForm> productList = Lists.newArrayListWithExpectedSize(size);
        Set<String> productNameList = Sets.newHashSetWithExpectedSize(size);
        BigDecimal totalPrice = BigDecimal.ZERO;
        DetectionOrderProductForm orderProductForm;
        for (DetectionProduct detectionProduct : detectionProducts) {
            orderProductForm = new DetectionOrderProductForm();
            orderProductForm.setProductId(detectionProduct.getId());
            orderProductForm.setProductName(detectionProduct.getProductName());
            String productItem = detectionProduct.getProductItem();
            if (StringUtils.isBlank(productItem)) {
                throw new BusinessException(String.format("【%s】未设置检测项，请联系客服", detectionProduct.getProductName()));
            }
            String itemNameVal = Stream.of(StringUtils.split(productItem, ",")).map(item -> item.concat(":正常"))
                .collect(Collectors.joining(","));
            orderProductForm.setItemNameVal(itemNameVal);
            productList.add(orderProductForm);
            productNameList.add(detectionProduct.getProductName());
            totalPrice = NumberUtil.add(detectionProduct.getPrice(), totalPrice);
        }
        DetectionOrder pojo = new DetectionOrder();

        String vendingMachineCode = form.getVendingMachineCode();
        if (StringUtils.isNotBlank(vendingMachineCode)) {
            DetectionTerminal vm = detectionTerminalService.findByCodeNo(vendingMachineCode, GlobalConst.NO);
            if (vm == null || EnableStatus.DISABLE.equals(vm.getEnabled())) {
                throw new BusinessException(String.format("贩卖机编号为【%s】无效，请联系客服", vendingMachineCode));
            }
            pojo.setVendingMachineId(vm.getId());
            pojo.setChannel(GlobalConst.PURCHASE_CHANNEL_VM);
        } else {
            pojo.setChannel(GlobalConst.PURCHASE_CHANNEL_RETAIL);
        }
        SeedltdUserDetails loginUser = UserUtils.getLoginUser();
        SysUser sysUser = sysUserService.findById(loginUser.getUserId());
        String productNames = StringUtils.join(productNameList, "、");
        String ipAddr = IPUtils.getIpAddr(request);
        String id = DateUtils.formatDate(new Date(), "yyMMdd") + SnowFlake.nextId();

        pojo.setUserId(loginUser.getUserId());
        pojo.setQrcodeId(0L);
        pojo.setTubeId(0L);
        pojo.setTradeNo(id);

        pojo.setTotalPrice(totalPrice);
        pojo.setRefundFlag(GlobalConst.NO);
        pojo.setState(OrderStatus.UNPAID.getValue());
        pojo.setCheckState(GlobalConst.CHECK_STATE_UNSTART);
        pojo.setProductNames(productNames);
        pojo.setBindingState(GlobalConst.NO);
        pojo.setExportFlag(GlobalConst.NO);
        pojo.setRemark(ipAddr);
        pojo.setDeleteFlag(GlobalConst.NO);
        baseMapper.insert(pojo);
        final Long orderId = pojo.getId();

        baseMapper.insertOrderProduct(orderId, productList);
        detectionOrderLogService.add(sysUser.getNickName(), new Date(), orderId, String.format("小程序下单，IP[%s]", ipAddr));
        detectionOrderTracingService.addByOrderId(orderId, String.valueOf(OrderStatus.UNPAID.getValue()));
        return orderId;
    }

    @Override
    public BasePage<DetectionOrderVO> page(DetectionOrderSearchForm searchForm) {
        String productNames = searchForm.getProductNames();
        boolean noting = false;
        if (StringUtils.isNotBlank(productNames)) {
            Set<Long> productIds = detectionProductService.selectIdByProductName(productNames);
            if (CollectionUtils.isNotEmpty(productIds)) {
                searchForm.setProductIdList(productIds);
            } else {
                noting = true;
            }
        }
        String qrcode = searchForm.getQrcode();
        if (StringUtils.isNotBlank(qrcode)) {
            DetectionQrcode detectionQrcode = detectionQrcodeService.findByCodeNo(qrcode, false);
            if (detectionQrcode != null) {
                searchForm.setQrcodeId(detectionQrcode.getId());
            } else {
                noting = true;
            }
        }

        String vendingMachineCode = searchForm.getVendingMachineCode();
        if (StringUtils.isNotBlank(vendingMachineCode)) {
            DetectionTerminal terminal = detectionTerminalService.findByCodeNo(qrcode, GlobalConst.NO);
            if (terminal != null) {
                searchForm.setVendingMachineId(terminal.getId());
            } else {
                noting = true;
            }
        }
        String recycleBinCode = searchForm.getRecycleBinCode();
        if (StringUtils.isNotBlank(recycleBinCode)) {
            DetectionTerminal terminal = detectionTerminalService.findByCodeNo(qrcode, GlobalConst.YES);
            if (terminal != null) {
                searchForm.setRecycleBinId(terminal.getId());
            } else {
                noting = true;
            }
        }
        BasePage<DetectionOrderVO> page = BasePage.of(searchForm.getStart(), searchForm.getSize());
        if (noting) {
            // 如果上述没有找到数据直接返回null
            return page;
        }
        return baseMapper.selectBgList(page, searchForm);
    }

    @Override
    public List<DetectionOrderVO> page(MiniOrderSearchForm form, Integer type) {
        BasePage<DetectionOrder> of = BasePage.of(form.getStart(), 6);
        of.setSearchCount(false);
        Long userId = UserUtils.getUserId();
        form.setUserId(userId);
        return baseMapper.list(of, form, GlobalConst.YES.equals(type));
    }

    @Override
    public List<DetectionOrderVO> listOrderDeliver() {
        Long userId = UserUtils.getUserId();
        return baseMapper.listOrderDeliver(userId);
    }

    @Override
    public String checkBinding(Long orderId, String qrcode) {
        DetectionQrcode detectionQrcode = detectionQrcodeService.findByCodeNo(qrcode, false);
        if (detectionQrcode == null) {
            return "二维码无效，请重新输入";
        }

        if (GlobalConst.QRCODE_STATE_INVALID.equals(detectionQrcode.getState())) {
            return "二维码已失效，请联系客服";
        }

        DetectionOrder idOrder = q().select(DetectionOrder::getId, DetectionOrder::getRefundFlag)
            .eq(DetectionOrder::getQrcodeId, detectionQrcode.getId()).selectOne();
        if (idOrder == null) {
            return null;
        } else if (!orderId.equals(idOrder.getId())) {
            return "二维码已被其它订单绑定，不能重复绑定";
        } else if (GlobalConst.YES.equals(idOrder.getRefundFlag())) {
            return "订单已退款，不能操作";
        }
        return null;
    }

    @Override
    @Transactional
    public boolean binding(DetectionOrderBindingForm form) {
        final Long orderId = form.getOrderId();
        DetectionOrder detectionOrder = this.getById(orderId);
        if (detectionOrder == null) {
            throw new BusinessException("订单号无效，请重新选择订单操作。");
        } else if (GlobalConst.YES.equals(detectionOrder.getRefundFlag())) {
            throw new BusinessException("订单已退款，不能操作");
        } else if (GlobalConst.YES.equals(detectionOrder.getDeleteFlag())) {
            throw new BusinessException("订单已删除，不能操作。");
        }

        final String qrCodeNumber = form.getCodeNumber();

        SeedltdUserDetails user = UserUtils.getLoginUser();
        if (!user.getUserId().equals(detectionOrder.getUserId())) {
            throw new BusinessException("只能操作自己的订单");
        }

        if (detectionOrder.getState() >= OrderStatus.CHECKING.getValue()) {
            OrderStatus enumByKey = EnumUtils.getEnumByKey(OrderStatus.class, detectionOrder.getState());
            throw new BusinessException("订单状态【%s】不能绑定采样者信息", enumByKey.getDesc());
        }

        DetectionQrcode detectionQrcode = detectionQrcodeService.findByCodeNo(qrCodeNumber, false);
        if (detectionQrcode == null) {
            throw new BusinessException("二维码【%s】无效，请核对或联系客户", qrCodeNumber);
        }

        DetectionOrder idOrder =
            q().select(DetectionOrder::getId).eq(DetectionOrder::getQrcodeId, detectionQrcode.getId()).selectOne();
        if (idOrder != null && !orderId.equals(idOrder.getId())) {
            throw new BusinessException("二维码【%s】已被其它订单绑定不能重复绑定", qrCodeNumber);
        }

        Integer qrcodeState = detectionQrcode.getState();
        if (GlobalConst.QRCODE_STATE_INVALID.equals(qrcodeState)) {
            throw new BusinessException("二维码【%s】无效，请核对或联系客户", qrCodeNumber);
        } else if (GlobalConst.QRCODE_STATE_BINDING.equals(qrcodeState)) {
            Long bindingOrderId = baseMapper.findIdByQrCodeId(detectionQrcode.getId());
            if (bindingOrderId != null && !orderId.equals(bindingOrderId)) {
                throw new BusinessException("二维码【%s】已绑定其它订单，请核对或联系客户", qrCodeNumber);
            }
        }

        DetectionTube detectionTube = detectionTubeService.findByQrCodeId(detectionQrcode.getId());
        Assert.notNull(detectionTube, "未找到试剂管信息，请联系客服。");

        // 设置绑定信息
        DetectionOrderBindingVO detectionOrderBindingVO = detectionOrderBindingService.findByOrderId(orderId);
        DetectionOrderBinding detectionOrderBinding = new DetectionOrderBinding();
        detectionOrderBinding.setOrderId(orderId);
        detectionOrderBinding.setSampleTime(form.getSampleTime());
        detectionOrderBinding.setUsername(form.getUsername());
        detectionOrderBinding.setAge(form.getAge());
        detectionOrderBinding.setGender(form.getGender());
        detectionOrderBinding.setMobile(form.getMobile());
        detectionOrderBinding.setSampleType(form.getSampleType());
        if (detectionOrderBindingVO != null) {
            detectionOrderBinding.setId(detectionOrderBindingVO.getId());
            detectionOrderBindingService.updateById(detectionOrderBinding);
        } else {
            detectionOrderBindingService.save(detectionOrderBinding);
        }

        DetectionOrder update = new DetectionOrder();
        update.setId(orderId);
        update.setTubeId(detectionTube.getId());
        update.setQrcodeId(detectionQrcode.getId());
        update.setBindingState(GlobalConst.YES);
        update.setResultScope(100);
        this.updateById(update);
        detectionOrderLogService.add(user.getNickName(), new Date(), orderId, "用户小程序提交绑定信息");
        return true;
    }

    @Override
    @Transactional
    public boolean deliver(final Long orderId, final String codeNo) {
        DetectionOrder detectionOrder = this.getById(orderId);
        if (detectionOrder == null) {
            throw new BusinessException("订单号无效，请重新选择订单操作。");
        } else if (GlobalConst.YES.equals(detectionOrder.getRefundFlag())) {
            throw new BusinessException("订单号【%s】已退款不能操作", detectionOrder.getTradeNo());
        } else if (GlobalConst.YES.equals(detectionOrder.getDeleteFlag())) {
            throw new BusinessException("订单已删除，不能操作。");
        }

        SeedltdUserDetails user = UserUtils.getLoginUser();
        if (!user.getUserId().equals(detectionOrder.getUserId())) {
            throw new BusinessException("只能操作自己的订单");
        }

        if (detectionOrder.getState() >= OrderStatus.CHECKING.getValue()) {
            OrderStatus enumByKey = EnumUtils.getEnumByKey(OrderStatus.class, detectionOrder.getState());
            throw new BusinessException(String.format("订单状态【%s】不能操作投递动作", enumByKey.getDesc()));
        }

        DetectionTerminal terminal = detectionTerminalService.findByCodeNo(codeNo, GlobalConst.YES);
        if (terminal == null || EnableStatus.DISABLE.equals(terminal.getEnabled())) {
            throw new BusinessException(String.format("终端编号【%s】无效，如有疑问请联系客服。", codeNo));
        }

        DetectionOrder order = new DetectionOrder();
        order.setId(orderId);
        order.setRecycleBinId(terminal.getId());
        order.setState(OrderStatus.DELIVER.getValue());
        this.updateById(order);

        detectionOrderLogService.add(user.getNickName(), new Date(), orderId, "用户小程序投递样本");
        detectionOrderTracingService.updateTracing(orderId, OrderStatus.DELIVER.getValue(), user.getNickName(),
            new Date(), false, null);

        Map<String, String> map = new HashMap<>();
        map.put("检测项目：", detectionOrder.getProductNames());
        map.put("投递箱编号：", terminal.getSerialNumber());
        map.put("投递箱所在地址：", terminal.getLocation());

        String content = Joiner.on("、").withKeyValueSeparator("：").join(map);

        threadPoolTaskExecutor.execute(() -> {
            DetectionMpConfigVO config = detectionMpConfigService.findById(1L);
            if (GlobalConst.YES.equals(config.getEnabledRb())) {
                String rbCc = config.getRbCc();
                String rbTo = config.getRbTo();
                try {
                    mailService.switchoverToRandom().send(StringUtils.split(rbTo, ","), StringUtils.split(rbCc, ","),
                        "用户投递样本通知", content);
                } catch (MessagingException e) {
                    log.error("发送用户投递通知异常：" + e.getMessage(), e);
                }
            }
        });

        return true;
    }

    @Override
    public DetectionOrderBindingSampleVO getBindingInfo(String codeNo) {
        DetectionQrcode detectionQrcode = detectionQrcodeService.findByCodeNo(codeNo, false);
        if (detectionQrcode == null) {
            throw new BusinessException(String.format("二维码【%s】编号无效", codeNo));
        }
        Integer state = detectionQrcode.getState();
        if (GlobalConst.QRCODE_STATE_UNBINDING.equals(state)) {
            throw new BusinessException(String.format("二维码【%s】编号没有绑定设备数据", codeNo));
        }
        if (GlobalConst.QRCODE_STATE_INVALID.equals(state)) {
            throw new BusinessException(String.format("二维码【%s】已失效", codeNo));
        }

        DetectionOrder detectionOrder = q().eq(DetectionOrder::getQrcodeId, detectionQrcode.getId()).selectOne();

        if (detectionOrder == null) {
            throw new BusinessException(String.format("未找到二维码【%s】绑定的订单信息", codeNo));
        }

        if (OrderStatus.DONE.getValue().equals(detectionOrder.getState())) {
            throw new BusinessException("订单已完成，不能重复操作");
        } else if (detectionOrder.getState() < OrderStatus.DELIVER.getValue()) {
            throw new BusinessException(String.format("订单状态【%s】不允许操作", detectionOrder.getState()));
        } else if (GlobalConst.YES.equals(detectionOrder.getRefundFlag())) {
            throw new BusinessException("订单已退款，不能操作");
        }

        Long orderId = detectionOrder.getId();

        if (OrderStatus.DELIVER.getValue().equals(detectionOrder.getState()) || detectionOrder.getCheckBy() == null) {
            SeedltdUserDetails loginUser = UserUtils.getLoginUser();
            DetectionOrder update = new DetectionOrder();
            update.setId(orderId);
            update.setCheckBy(loginUser.getUserId());
            update.setCheckTime(new Date());
            update.setState(OrderStatus.CHECKING.getValue());
            this.updateById(update);
            detectionOrderLogService.add(loginUser.toString(), new Date(), orderId, "获取检测绑定人数据，并且修改状态为：检测中");
            detectionOrderTracingService.updateTracing(orderId, OrderStatus.CHECKING.getValue(),
                loginUser.getNickName(), new Date(), false, null);
        }

        DetectionOrderBindingVO binding = detectionOrderBindingService.findByOrderId(orderId);
        DetectionOrderBindingSampleVO detectionOrderBindingSampleVO = new DetectionOrderBindingSampleVO();
        detectionOrderBindingSampleVO.setGender(binding.getGender());
        detectionOrderBindingSampleVO.setUsername(binding.getUsername());
        detectionOrderBindingSampleVO.setProductNames(detectionOrder.getProductNames());
        detectionOrderBindingSampleVO.setCodeNo(codeNo);
        detectionOrderBindingSampleVO.setAge(binding.getAge());
        return detectionOrderBindingSampleVO;
    }

    @Override
    @Transactional
    public boolean refund(DetectionOrderRefundForm refundForm) {
        final Long orderId = refundForm.getOrderId();
        DetectionOrder order = this.getById(orderId);
        if (order == null) {
            throw new BusinessException("未找到需要退款的订单");
        }

        if (OrderStatus.UNPAID.getValue().equals(order.getState())) {
            throw new BusinessException("未支付的订单不需要退款");
        }

        if (GlobalConst.YES.equals(order.getRefundFlag())) {
            throw new BusinessException("已退款，不能重复退款");
        }

        if (GlobalConst.YES.equals(order.getDeleteFlag())) {
            throw new BusinessException("订单已删除，不能操作。");
        }

        BigDecimal totalPrice = order.getTotalPrice();

        BigDecimal refundPrice = refundForm.getRefundPrice();
        if (refundPrice == null) {
            refundPrice = totalPrice;
        } else if (NumberUtil.isGreater(refundPrice, totalPrice)) {
            throw new BusinessException("退款金额不能大于订单金额");
        }

        final String outRefundNo = IdUtil.fastSimpleUUID();
        SeedltdUserDetails loginUser = UserUtils.getLoginUser();

        DetectionOrderRefund refundVO = detectionOrderRefundService.getByOrderId(orderId);
        boolean isUpdate = true;
        if (refundVO == null) {
            isUpdate = false;
            refundVO = new DetectionOrderRefund();
            refundVO.setOrderId(orderId);
            refundVO.setRefundNo(outRefundNo);
            refundVO.setRefundBy(loginUser.getNickName());
            refundVO.setRefundTime(new Date());
            refundVO.setRefundReason(refundForm.getRefundReason());
            refundVO.setRefundPrice(refundPrice.toString());
        }
        String refundState = refundVO.getRefundState();

        if (StringUtils.isNotBlank(refundState)) {
            throw new BusinessException(String.format("退款状态【%s】不允许二次操作", refundState));
        }

        RefundOrderDTO refundOrderDTO = new RefundOrderDTO();
        refundOrderDTO.setRefund(refundPrice);
        refundOrderDTO.setOutRefundNo(outRefundNo);
        refundOrderDTO.setReason(refundForm.getRefundReason());
        refundOrderDTO.setOutTradeNo(order.getTradeNo());
        refundOrderDTO.setTotal(totalPrice);

        RefundVO refund;
        try {
            refund = detectionWeCharPayService.refund(refundOrderDTO);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }

        refundVO.setRefundState(refund.getStatus());
        refundVO.setRefundId(refund.getRefundId());
        refundVO.setUserReceivedAccount(refund.getUserReceivedAccount());
        refundVO.setUserReceivedAccount(refund.getUserReceivedAccount());

        DetectionOrder update = new DetectionOrder();
        update.setId(orderId);
        update.setRefundFlag(GlobalConst.YES);

        this.updateById(update);
        if (isUpdate) {
            detectionOrderRefundService.updateById(refundVO);
        } else {
            detectionOrderRefundService.save(refundVO);
        }
        detectionOrderLogService.add(loginUser.getNickName(), new Date(), orderId,
            String.format("用户登入账号【%s】发起订单退款，退款金额为：【%s】,退款说明：【%s】", loginUser.getLoginName(), refundPrice.toString(),
                refundForm.getRefundReason()));
        return true;
    }

    @Override
    @Transactional
    public boolean exportGoods(Long orderId, boolean isBg) {
        DetectionOrder notifyExportOrder = this.getNotifyExportOrder(orderId, isBg);
        Long vendingMachineId = notifyExportOrder.getVendingMachineId();
        DetectionTerminal detectionTerminal = detectionTerminalService.getById(vendingMachineId);
        Assert.notNull(detectionTerminal, "未找到订单号关联的售卖机");

        if (EnableStatus.DISABLE.equals(detectionTerminal.getEnabled())) {
            throw new BusinessException("售卖机已禁用不能发货");
        }
        DetectionTerminalPipeline terminalPipeline = detectionTerminalPipelineService.getByTerminalId(vendingMachineId);
        String arrivalName = terminalPipeline.getArrivalName();

        SeedltdUserDetails loginUser = UserUtils.getLoginUser();
        String msg;
        String response;
        try {
            response = vendingMachineApiService.notifyExport(detectionTerminal.getMachineId(),
                notifyExportOrder.getTradeNo(), arrivalName);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            msg = String.format("触发售卖机出货失败：%s", e.getMessage());
            throw new BusinessException(msg);
        }
        u().set(DetectionOrder::getExportFlag, GlobalConst.YES).eq(DetectionOrder::getId, orderId).update();
        msg = String.format("触发售卖机出货成功：%s", response);

        // 减去货道的数量，这里不考虑并发的问题。同一个售卖机不会同时有多个人支付购买。
        // 并且不需要处理库存，因为每五分钟会同步一次库存
        detectionTerminalPipelineService.updatePipelineNumber(terminalPipeline.getId(),
            terminalPipeline.getPresentNumber() - 1);

        detectionOrderLogService.add(loginUser.getNickName(), new Date(), orderId, msg);
        return true;
    }

    @Override
    @Transactional
    public boolean deleteByOrderId(final Long orderId) {
        DetectionOrder detectionOrder = this.getById(orderId);
        Assert.notNull(detectionOrder, "未找到订单数据");

        SeedltdUserDetails user = UserUtils.getLoginUser();
        if (!user.getUserId().equals(detectionOrder.getUserId())) {
            throw new BusinessException("只能操作自己的订单");
        }

        detectionOrderLogService.add(user.getNickName(), new Date(), orderId, "删除订单");

        DetectionOrder order = new DetectionOrder();
        order.setId(orderId);
        order.setDeleteFlag(GlobalConst.YES);
        return u(order).updateById();
    }
}